#pragma once
#include"Common.hpp"
#define MAX_LISTEN_BACKLOG 1024

class TcpSocket
{
private:
    bool CreateSocket()
    {
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(FATAL, "创建套接字失败!\n");
            return false;
        }
        LOG(DEBUG, "创建套接字成功!,sockfd = %d\n", _sockfd);
        return true;
    }
    // 设置描述符非阻塞
    void SetFdNoBlock(int fd)
    {
        // 先获取描述符状态
        // int flag = ::fcntl(fd, F_GETFL);
        int flag = ::fcntl(fd, F_GETFL,0);//修改
        // 设置非阻塞
        ::fcntl(fd, F_SETFL, flag | O_NONBLOCK);
    }
    bool BindSocket(uint16_t port)
    {
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        peer.sin_family = AF_INET;
        peer.sin_addr.s_addr = INADDR_ANY;
        peer.sin_port = ::htons(port);
        if (::bind(_sockfd, (struct sockaddr *)&peer, sizeof(peer)) < 0)
        {
            LOG(FATAL, "绑定ip和端口失败!\n");
            return false;
        }
        LOG(DEBUG, "绑定ip和端口完毕!\n");
        return true;
    }
    // ip地址复用
    void RetryAddress()
    {
        int opt = 1;
        ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
        opt = 1;
        ::setsockopt(_sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
        LOG(DEBUG, "设置地址复用完毕!\n");
    }
    bool ListenSocket(int block = MAX_LISTEN_BACKLOG)
    {
        // 监听连接请求
        if (::listen(_sockfd, block) < 0)
        {
            LOG(FATAL, "listen error!\n");
            return false;
        }
        LOG(DEBUG, "listen succss!\n");
        return true;
    }

public:
    TcpSocket() : _sockfd(-1)
    {
    }
    TcpSocket(int sockfd) : _sockfd(sockfd)
    {
        // SetFdNoBlock(_sockfd);//修改第二处
    }
    ~TcpSocket()
    {
        // if (_sockfd > 0)
        // {
        //     ::close(_sockfd);
        // }//第三处
    }
    int SockFd()
    {
        return _sockfd;
    }
    int AcceptSocket()
    {
        // 不关心client具体ip
        int sockfd = ::accept(_sockfd, nullptr, nullptr);
        if (sockfd < 0)
        {
            LOG(ERROR, "获取新连接异常!\n");
            return -1;
        }
        return sockfd;
    }
    bool Connect(const std::string &serverip, uint16_t port) // 客户端
    {
        struct sockaddr_in server; // 发送给谁？？ server！！
        memset(&server, 0, sizeof(server));
        // 填充servrip && port
        server.sin_family = AF_INET;
        // server.sin_addr.s_addr = inet_addr(serverip.c_str());
        if (::inet_pton(AF_INET, serverip.c_str(), &server.sin_addr) != 1)
        {
            LOG(ERROR, "ip地址无效!\n");
            return false;
        }
        server.sin_port = ::htons(port);
        int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
        if (n < 0)
        {
            LOG(ERROR, "连接异常!\n");
            return false;
        }
        return true;
    }
    void Close()
    {
        if (_sockfd != -1)
        {
            ::close(_sockfd);
            LOG(DEBUG, "套接字已关闭,fd = %d\n", _sockfd);
            _sockfd = -1;
        }
    }
    bool CreateServer(uint16_t port, bool block_enable = false, int backlog = MAX_LISTEN_BACKLOG)
    {
        if (!CreateSocket())
        {
            return false;
        }
        // 设置ip+端口地址复用
        RetryAddress();
        if (block_enable)
        {
            // 如果上层设置了开启标记位就设置为非阻塞
            SetFdNoBlock(_sockfd);
        }
        if (!BindSocket(port))
        {
            return false;
        }
        if (!ListenSocket(backlog))
        {
            return false;
        }
        LOG(DEBUG, "Tcp套接字初始化完毕!\n");
        return true;
    }
    bool CreateClient(const std::string &ip, uint16_t port)
    {
        // 1. 创建套接字，2.指向连接服务器
        if (!CreateSocket())
            return false;
        if (!Connect(ip, port))
            return false;
        LOG(DEBUG, "初始化客户端套接字完毕!\n");
        return true;
    }
    ssize_t Send(const void *in, size_t len)
    {
        // if (len == 0)
        //     return 0;//修改一处
        ssize_t n = ::send(_sockfd, in, len, MSG_DONTWAIT);
        if (n < 0)
        {
            if (errno == EINTR || errno == EAGAIN)
            {
                return 0;
            }
            LOG(ERROR, "本次发送数据操作异常!,n = %d\n", n);
            return -1;
        }
        LOG(DEBUG, "发送数据完毕,发送字节:%d\n", n);
        return n;
    }
    ssize_t Recv(void *in, size_t len)
    {
        ssize_t n = ::recv(_sockfd, in, len, MSG_DONTWAIT);
        if (n <= 0)  // 这个地方是非阻塞读取的，返回值的n是会<=0的，具体是读取错误还是没有数据，是根据标记位判断的
        {
            if (errno == EINTR || errno == EAGAIN)
            {
                return 0;
            }
            LOG(ERROR, "本次接收数据操作异常!,n = %d\n", n);
            return -1;
        }
        LOG(DEBUG, "接收数据完毕,接收字节:%d\n", n);
        return n;
    }

private:
    int _sockfd;
};